/*
 * Copyright (c) Jiandong.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */


import hilog from '@ohos.hilog';
import HashMap from '@ohos.util.HashMap';
import systemTime from '@ohos.systemTime';
import Context from '@ohos.application.context';

import { PackagerCommandListener } from './DevServerHelper';
import { BundleInfo } from './BundleDownloader';
import { BundleStatusProvider } from './InspectorPackagerConnection';
import { DevInternalSettings } from './DevInternalSettings';
import { RequestHandler } from '../packagerConnection/RequestHandler';
import { Assertions } from '../inner/Assertions';
import { BundleLoadCallback } from './BundleLoadCallback';
import { PackagerStatusCallback } from './PackagerStatusCallback';
import { DevServerHelper } from './DevServerHelper';
import { ReactInstanceDevHelper } from './ReactInstanceDevHelper';
import { ReactContext } from '../bridge/ReactContext';
import { BundleStatus } from './InspectorPackagerConnection';
import { DevBundleDownloadListener } from './DevBundleDownloadListener';
import { SurfaceDelegateFactory } from '../common/SurfaceDelegateFactory';
import { DevSupportManager } from './DevSupportManager';
import { JSBundleLoader } from '../bridge/JSBundleLoader';
import { SurfaceDelegate } from '../common/SurfaceDelegate';


export abstract class DevSupportManagerBase implements DevSupportManager {
  private static readonly TAG: string = "React DevSupportManagerBase"
  public static readonly EMOJI_HUNDRED_POINTS_SYMBOL = " \ud83d\udcaf";
  public static readonly EMOJI_FACE_WITH_NO_GOOD_GESTURE = " \ud83d\ude45";
  private static readonly JAVA_ERROR_COOKIE = -1;
  private static readonly JSEXCEPTION_ERROR_COOKIE = -1;
  private static readonly RELOAD_APP_ACTION_SUFFIX = ".RELOAD_APP_ACTION";
  private static readonly FLIPPER_DEBUGGER_URL = "flipper://null/Hermesdebuggerrn?device=React%20Native";
  private static readonly FLIPPER_DEVTOOLS_URL = "flipper://null/React?device=React%20Native";
  private static readonly EXOPACKAGE_LOCATION_FORMAT = "/data/local/tmp/exopackage/%s//secondary-dex";
  private static mID: number = 0;
  //  private readonly ShakeDetector mShakeDetector;
  private readonly mAbilityContext: Context.AbilityContext
  //  private readonly BroadcastReceiver mReloadAppBroadcastReceiver;
  private readonly mDevServerHelper: DevServerHelper;
  //  private readonly LinkedHashMap<String, DevOptionHandler> mCustomDevOptions = new LinkedHashMap();
  private readonly mReactInstanceDevHelper: ReactInstanceDevHelper;
  private readonly mJSAppBundleName?: string;
  private readonly mJSBundleDownloadedFile: string // File;
  //  private readonly DefaultJSExceptionHandler mDefaultJSExceptionHandler;
  //  private readonly DevLoadingViewController mDevLoadingViewController;
  private readonly mJSSplitBundlesDir: string // File;
  //  @Nullable
  //  private AlertDialog mDevOptionsDialog;
  //  @Nullable
  //  private DebugOverlayController mDebugOverlayController;
  //  private boolean mDevLoadingViewVisible = false;
  private mRedBoxSurfaceDelegate?: SurfaceDelegate;
  //  private int mPendingJSSplitBundleRequests = 0;
  private mCurrentContext?: ReactContext;
  private mDevSettings: DevInternalSettings;
  private mIsReceiverRegistered: boolean = false;
  private mIsShakeDetectorStarted: boolean = false;
  //  @Nullable
  //  private RedBoxHandler mRedBoxHandler;
  //  @Nullable
  //  private String mLastErrorTitle;
  //  @Nullable
  //  private StackFrame[] mLastErrorStack;
  //  @Nullable
  //  private ErrorType mLastErrorType;
  //  private int mLastErrorCookie = 0;
  private mIsDevSupportEnabled: boolean = false;
  //  @Nullable
  //  private List<ErrorCustomizer> mErrorCustomizers;
  //  @Nullable
  //  @Nullable
  private mBundleDownloadListener?: DevBundleDownloadListener;
  //  private PackagerLocationCustomizer mPackagerLocationCustomizer;
  private mBundleStatus: BundleStatus;
  //  @Nullable
  //  private Activity currentActivity;
  //  @Nullable
  private mCustomPackagerCommandHandlers?: HashMap<string, RequestHandler>;
  //  @Nullable
  private readonly mSurfaceDelegateFactory?: SurfaceDelegateFactory;

  public constructor(abilityContext: Context.AbilityContext, reactInstanceDevHelper: ReactInstanceDevHelper,
                     packagerPathForJSBundleName: string, enableOnCreate: boolean,
                     /*@Nullable RedBoxHandler redBoxHandler,*/
                     devBundleDownloadListener: DevBundleDownloadListener,
                     minNumShakes: number, customPackagerCommandHandlers: HashMap<string, RequestHandler>,
                     surfaceDelegateFactory: SurfaceDelegateFactory) {
    hilog.info(0x0000, DevSupportManagerBase.TAG, 'constructor');
    this.mReactInstanceDevHelper = reactInstanceDevHelper;
    this.mAbilityContext = abilityContext;
    this.mJSAppBundleName = packagerPathForJSBundleName;
    this.mDevSettings = new DevInternalSettings(abilityContext /*, new Listener() {
            public void onInternalSettingsChanged() {
                DevSupportManagerBase.this.reloadSettings();
            }
        }*/
    );
    this.mBundleStatus = new BundleStatus();
    this.mDevServerHelper = new DevServerHelper(this.mDevSettings, this.mAbilityContext.abilityInfo.bundleName, ((base: DevSupportManagerBase) => {
      return new class temp extends BundleStatusProvider {
        constructor(private mBase: DevSupportManagerBase) {
          super()
        }

        public getBundleStatus(): BundleStatus {
          return this.mBase.mBundleStatus;
        }
      } (base)
    })(this));


    this.mBundleDownloadListener = devBundleDownloadListener;
    //this.mShakeDetector = new ShakeDetector(new ShakeListener() {
    //            public void onShake() {
    //                DevSupportManagerBase.this.showDevOptionsDialog();
    //            }
    //}, minNumShakes);
    this.mCustomPackagerCommandHandlers = customPackagerCommandHandlers;
    //this.mReloadAppBroadcastReceiver = new BroadcastReceiver() {
    //            public void onReceive(Context context, Intent intent) {
    //                String action = intent.getAction();
    //                if (DevSupportManagerBase.getReloadAppAction(context).equals(action)) {
    //                    if (intent.getBooleanExtra("jsproxy", false)) {
    //                        DevSupportManagerBase.this.mDevSettings.setRemoteJSDebugEnabled(true);
    //                        DevSupportManagerBase.this.mDevServerHelper.launchJSDevtools();
    //                    } else {
    //  DevSupportManagerBase.this.mDevSettings.setRemoteJSDebugEnabled(false);
    //}
    //
    //DevSupportManagerBase.this.handleReloadJS();
    //}
    //
    //}
    //};
    let subclassTag: string = this.getUniqueTag();
    let bundleFile: string = subclassTag + "ReactNativeDevBundle.js";
    this.mJSBundleDownloadedFile = abilityContext.filesDir + "\/"+ bundleFile// new File(applicationContext.getFilesDir(), bundleFile);

    hilog.info(0x0000, DevSupportManagerBase.TAG, 'constructor: mJSBundleDownloadedFile' + this.mJSBundleDownloadedFile);


    //String splitBundlesDir = subclassTag.toLowerCase(Locale.ROOT) + "_dev_js_split_bundles";
    //this.mJSSplitBundlesDir = this.mApplicationContext.getDir(splitBundlesDir, 0);
    //this.mDefaultJSExceptionHandler = new DefaultJSExceptionHandler();
    this.setDevSupportEnabled(enableOnCreate);
    //this.mRedBoxHandler = redBoxHandler;
    //this.mDevLoadingViewController = new DevLoadingViewController(reactInstanceDevHelper);
    this.mSurfaceDelegateFactory = surfaceDelegateFactory;
  }

  private static generateID(): string {
    return "dev" + DevSupportManagerBase.mID++
  }

  public handleException(e: Error): void {
    if (this.mIsDevSupportEnabled) {
      //this.logJSException(e);
    } else {
      // this.mDefaultJSExceptionHandler.handleException(e);
    }
  }

  public setDevSupportEnabled(isDevSupportEnabled: boolean) {
    this.mIsDevSupportEnabled = isDevSupportEnabled;
    //this.reloadSettings();
  }
  //
  //private void logJSException(Exception e) {
  //        StringBuilder message = new StringBuilder(e.getMessage() == null ? "Exception in native call from JS" : e.getMessage());
  //
  //        for(Throwable cause = e.getCause(); cause != null; cause = cause.getCause()) {
  //            message.append("\n\n").append(cause.getMessage());
  //        }
  //
  //if (e instanceof JSException) {
  //            FLog.e("ReactNative", "Exception in native call from JS", e);
  //            String stack = ((JSException)e).getStack();
  //            message.append("\n\n").append(stack);
  //            this.showNewError(message.toString(), new StackFrame[0], -1, ErrorType.JS);
  //        } else {
  //  this.showNewJavaError(message.toString(), e);
  //}
  //
  //}
  //
  //public void showNewJavaError(@Nullable String message, Throwable e) {
  //  FLog.e("ReactNative", "Exception in native call", e);
  //  this.showNewError(message, StackTraceHelper.convertJavaStackTrace(e), -1, ErrorType.NATIVE);
  //}
  //
  //public void addCustomDevOption(String optionName, DevOptionHandler optionHandler) {
  //  this.mCustomDevOptions.put(optionName, optionHandler);
  //}
  //
  //public void showNewJSError(String message, ReadableArray details, int errorCookie) {
  //  this.showNewError(message, StackTraceHelper.convertJsStackTrace(details), errorCookie, ErrorType.JS);
  //}
  //
  //public void registerErrorCustomizer(ErrorCustomizer errorCustomizer) {
  //  if (this.mErrorCustomizers == null) {
  //    this.mErrorCustomizers = new ArrayList();
  //  }
  //
  //  this.mErrorCustomizers.add(errorCustomizer);
  //}
  //
  //public Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo) {
  //  if (this.mErrorCustomizers == null) {
  //    return errorInfo;
  //  } else {
  //            Iterator var2 = this.mErrorCustomizers.iterator();
  //
  //            while(var2.hasNext()) {
  //                ErrorCustomizer errorCustomizer = (ErrorCustomizer)var2.next();
  //                Pair<String, StackFrame[]> result = errorCustomizer.customizeErrorInfo(errorInfo);
  //                if (result != null) {
  //                    errorInfo = result;
  //                }
  //}
  //
  //return errorInfo;
  //}
  //}
  //
  //public void updateJSError(final String message, final ReadableArray details, final int errorCookie) {
  //        UiThreadUtil.runOnUiThread(new Runnable() {
  //            public void run() {
  //                if (DevSupportManagerBase.this.mRedBoxSurfaceDelegate.isShowing() && errorCookie == DevSupportManagerBase.this.mLastErrorCookie) {
  //                    DevSupportManagerBase.this.updateLastErrorInfo(message, StackTraceHelper.convertJsStackTrace(details), errorCookie, ErrorType.JS);
  //                    DevSupportManagerBase.this.mRedBoxSurfaceDelegate.show();
  //                }
  //            }
  //        });
  //    }
  //
  //public void hideRedboxDialog() {
  //  if (this.mRedBoxSurfaceDelegate != null) {
  //    this.mRedBoxSurfaceDelegate.hide();
  //  }
  //}
  //
  //@Nullable
  //public View createRootView(String appKey) {
  //  return this.mReactInstanceDevHelper.createRootView(appKey);
  //}
  //
  //public void destroyRootView(View rootView) {
  //  this.mReactInstanceDevHelper.destroyRootView(rootView);
  //}
  //
  //private void hideDevOptionsDialog() {
  //  if (this.mDevOptionsDialog != null) {
  //    this.mDevOptionsDialog.dismiss();
  //    this.mDevOptionsDialog = null;
  //  }
  //
  //}
  //
  //private void showNewError(@Nullable final String message, final StackFrame[] stack, final int errorCookie, final ErrorType errorType) {
  //        UiThreadUtil.runOnUiThread(new Runnable() {
  //            public void run() {
  //                DevSupportManagerBase.this.updateLastErrorInfo(message, stack, errorCookie, errorType);
  //                if (DevSupportManagerBase.this.mRedBoxSurfaceDelegate == null) {
  //                    SurfaceDelegate redBoxSurfaceDelegate = DevSupportManagerBase.this.createSurfaceDelegate("RedBox");
  //                    if (redBoxSurfaceDelegate != null) {
  //                        DevSupportManagerBase.this.mRedBoxSurfaceDelegate = redBoxSurfaceDelegate;
  //                    } else {
  //                        DevSupportManagerBase.this.mRedBoxSurfaceDelegate = new RedBoxDialogSurfaceDelegate(DevSupportManagerBase.this);
  //                    }
  //
  //                    DevSupportManagerBase.this.mRedBoxSurfaceDelegate.createContentView("RedBox");
  //                }
  //
  //                if (!DevSupportManagerBase.this.mRedBoxSurfaceDelegate.isShowing()) {
  //                    DevSupportManagerBase.this.mRedBoxSurfaceDelegate.show();
  //                }
  //            }
  //        });
  //    }
  //
  //public void showDevOptionsDialog() {
  //        if (this.mDevOptionsDialog == null && this.mIsDevSupportEnabled && !ActivityManager.isUserAMonkey()) {
  //            LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap();
  //            options.put(this.mApplicationContext.getString(string.catalyst_reload), new DevOptionHandler() {
  //                public void onOptionSelected() {
  //                    if (!DevSupportManagerBase.this.mDevSettings.isJSDevModeEnabled() && DevSupportManagerBase.this.mDevSettings.isHotModuleReplacementEnabled()) {
  //                        Toast.makeText(DevSupportManagerBase.this.mApplicationContext, DevSupportManagerBase.this.mApplicationContext.getString(string.catalyst_hot_reloading_auto_disable), 1).show();
  //                        DevSupportManagerBase.this.mDevSettings.setHotModuleReplacementEnabled(false);
  //                    }
  //
  //                    DevSupportManagerBase.this.handleReloadJS();
  //                }
  //            });
  //            if (this.mDevSettings.isDeviceDebugEnabled()) {
  //                if (this.mDevSettings.isRemoteJSDebugEnabled()) {
  //                    this.mDevSettings.setRemoteJSDebugEnabled(false);
  //                    this.handleReloadJS();
  //                }
  //
  //                options.put(this.mApplicationContext.getString(string.catalyst_debug_open), new DevOptionHandler() {
  //                    public void onOptionSelected() {
  //                        DevSupportManagerBase.this.mDevServerHelper.openUrl(DevSupportManagerBase.this.mCurrentContext, "flipper://null/Hermesdebuggerrn?device=React%20Native", DevSupportManagerBase.this.mApplicationContext.getString(string.catalyst_open_flipper_error));
  //                    }
  //                });
  //                options.put(this.mApplicationContext.getString(string.catalyst_devtools_open), new DevOptionHandler() {
  //                    public void onOptionSelected() {
  //                        DevSupportManagerBase.this.mDevServerHelper.openUrl(DevSupportManagerBase.this.mCurrentContext, "flipper://null/React?device=React%20Native", DevSupportManagerBase.this.mApplicationContext.getString(string.catalyst_open_flipper_error));
  //                    }
  //                });
  //            }
  //
  //options.put(this.mApplicationContext.getString(string.catalyst_change_bundle_location), new DevOptionHandler() {
  //                public void onOptionSelected() {
  //                    Activity context = DevSupportManagerBase.this.mReactInstanceDevHelper.getCurrentActivity();
  //                    if (context != null && !context.isFinishing()) {
  //                        final EditText input = new EditText(context);
  //                        input.setHint("localhost:8081");
  //                        AlertDialog bundleLocationDialog = (new Builder(context)).setTitle(DevSupportManagerBase.this.mApplicationContext.getString(string.catalyst_change_bundle_location)).setView(input).setPositiveButton(17039370, new OnClickListener() {
  //                            public void onClick(DialogInterface dialog, int which) {
  //                                String host = input.getText().toString();
  //                                DevSupportManagerBase.this.mDevSettings.getPackagerConnectionSettings().setDebugServerHost(host);
  //                                DevSupportManagerBase.this.handleReloadJS();
  //                            }
  //                        }).create();
  //                        bundleLocationDialog.show();
  //                    } else {
  //  FLog.e("ReactNative", "Unable to launch change bundle location because react activity is not available");
  //}
  //}
  //});
  //options.put(this.mDevSettings.isElementInspectorEnabled() ? this.mApplicationContext.getString(string.catalyst_inspector_stop) : this.mApplicationContext.getString(string.catalyst_inspector), new DevOptionHandler() {
  //                public void onOptionSelected() {
  //                    DevSupportManagerBase.this.mDevSettings.setElementInspectorEnabled(!DevSupportManagerBase.this.mDevSettings.isElementInspectorEnabled());
  //                    DevSupportManagerBase.this.mReactInstanceDevHelper.toggleElementInspector();
  //                }
  //});
  //options.put(this.mDevSettings.isHotModuleReplacementEnabled() ? this.mApplicationContext.getString(string.catalyst_hot_reloading_stop) : this.mApplicationContext.getString(string.catalyst_hot_reloading), new DevOptionHandler() {
  //                public void onOptionSelected() {
  //                    boolean nextEnabled = !DevSupportManagerBase.this.mDevSettings.isHotModuleReplacementEnabled();
  //                    DevSupportManagerBase.this.mDevSettings.setHotModuleReplacementEnabled(nextEnabled);
  //                    if (DevSupportManagerBase.this.mCurrentContext != null) {
  //                        if (nextEnabled) {
  //                            ((HMRClient)DevSupportManagerBase.this.mCurrentContext.getJSModule(HMRClient.class)).enable();
  //                        } else {
  //                            ((HMRClient)DevSupportManagerBase.this.mCurrentContext.getJSModule(HMRClient.class)).disable();
  //                        }
  //}
  //
  //if (nextEnabled && !DevSupportManagerBase.this.mDevSettings.isJSDevModeEnabled()) {
  //  Toast.makeText(DevSupportManagerBase.this.mApplicationContext, DevSupportManagerBase.this.mApplicationContext.getString(string.catalyst_hot_reloading_auto_enable), 1).show();
  //  DevSupportManagerBase.this.mDevSettings.setJSDevModeEnabled(true);
  //  DevSupportManagerBase.this.handleReloadJS();
  //}
  //
  //}
  //});
  //options.put(this.mDevSettings.isFpsDebugEnabled() ? this.mApplicationContext.getString(string.catalyst_perf_monitor_stop) : this.mApplicationContext.getString(string.catalyst_perf_monitor), new DevOptionHandler() {
  //                public void onOptionSelected() {
  //                    if (!DevSupportManagerBase.this.mDevSettings.isFpsDebugEnabled()) {
  //                        Context context = DevSupportManagerBase.this.mReactInstanceDevHelper.getCurrentActivity();
  //                        if (context == null) {
  //                            FLog.e("ReactNative", "Unable to get reference to react activity");
  //                        } else {
  //  DebugOverlayController.requestPermission(context);
  //}
  //}
  //
  //DevSupportManagerBase.this.mDevSettings.setFpsDebugEnabled(!DevSupportManagerBase.this.mDevSettings.isFpsDebugEnabled());
  //}
  //});
  //options.put(this.mApplicationContext.getString(string.catalyst_settings), new DevOptionHandler() {
  //                public void onOptionSelected() {
  //                    Intent intent = new Intent(DevSupportManagerBase.this.mApplicationContext, DevSettingsActivity.class);
  //                    intent.setFlags(268435456);
  //                    DevSupportManagerBase.this.mApplicationContext.startActivity(intent);
  //                }
  //});
  //if (this.mCustomDevOptions.size() > 0) {
  //  options.putAll(this.mCustomDevOptions);
  //}
  //
  //final DevOptionHandler[] optionHandlers = (DevOptionHandler[])options.values().toArray(new DevOptionHandler[0]);
  //Activity context = this.mReactInstanceDevHelper.getCurrentActivity();
  //if (context != null && !context.isFinishing()) {
  //                TextView textView = new TextView(this.getApplicationContext());
  //                textView.setText("React Native DevMenu (" + this.getUniqueTag() + ")");
  //                textView.setPadding(0, 50, 0, 0);
  //                textView.setGravity(17);
  //                textView.setTextColor(-16777216);
  //                textView.setTextSize(17.0F);
  //                textView.setTypeface(textView.getTypeface(), 1);
  //                this.mDevOptionsDialog = (new Builder(context)).setCustomTitle(textView).setItems((CharSequence[])options.keySet().toArray(new String[0]), new OnClickListener() {
  //                    public void onClick(DialogInterface dialog, int which) {
  //                        optionHandlers[which].onOptionSelected();
  //                        DevSupportManagerBase.this.mDevOptionsDialog = null;
  //                    }
  //                }).setOnCancelListener(new OnCancelListener() {
  //                    public void onCancel(DialogInterface dialog) {
  //                        DevSupportManagerBase.this.mDevOptionsDialog = null;
  //                    }
  //                }).create();
  //                this.mDevOptionsDialog.show();
  //                if (this.mCurrentContext != null) {
  //                    ((RCTNativeAppEventEmitter)this.mCurrentContext.getJSModule(RCTNativeAppEventEmitter.class)).emit("RCTDevMenuShown", (Object)null);
  //                }
  //
  //} else {
  //  FLog.e("ReactNative", "Unable to launch dev options menu because react activity isn't available");
  //}
  //}
  //}

  public getDevSupportEnabled(): boolean {
    return this.mIsDevSupportEnabled;
  }

  public getDevSettings(): DevInternalSettings {
    return this.mDevSettings;
  }

  public onNewReactContextCreated(reactContext: ReactContext): void {
    this.resetCurrentContext(reactContext);
  }
  //
  //public RedBoxHandler getRedBoxHandler() {
  //  return this.mRedBoxHandler;
  //}

  public onReactInstanceDestroyed(reactContext: ReactContext): void {
    if (reactContext == this.mCurrentContext) {
      this.resetCurrentContext(null);
    }

  }

  public getSourceMapUrl(): string {
    //        Assertions.assertNotNull(this.mJSAppBundleName != null)
    return this.mJSAppBundleName == null ? "" : this.mDevServerHelper.getSourceMapUrl(this.mJSAppBundleName);
  }

  public getSourceUrl(): string {
    //        Assertions.assertNotNull(this.mJSAppBundleName != null)
    return this.mJSAppBundleName == null ? "" : this.mDevServerHelper.getSourceUrl(this.mJSAppBundleName);
  }

  public getJSBundleURLForRemoteDebugging(): string {
    Assertions.assertNotNull(this.mJSAppBundleName != null)
    return this.mDevServerHelper.getJSBundleURLForRemoteDebugging(this.mJSAppBundleName);
  }

  public getDownloadedJSBundleFile(): string {
//    return this.mJSBundleDownloadedFile.getAbsolutePath();
    return this.mJSBundleDownloadedFile;
  }

  public hasUpToDateJSBundleInCache(): boolean {
    if (this.mIsDevSupportEnabled && this.mJSBundleDownloadedFile != null) { //.exists()) {
      try {
        //                let packageName: string = this.mApplicationContext.getPackageName();
        //                PackageInfo thisPackage = this.mApplicationContext.getPackageManager().getPackageInfo(packageName, 0);
        //                if (this.mJSBundleDownloadedFile.lastModified() > thisPackage.lastUpdateTime) {
        //                    File exopackageDir = new File(String.format(Locale.US, "/data/local/tmp/exopackage/%s//secondary-dex", packageName));
        //                    if (exopackageDir.exists()) {
        //                        return this.mJSBundleDownloadedFile.lastModified() > exopackageDir.lastModified();
        //                    }
        //
        //    return true;
        //  }
      } catch (var4: any) {
        //FLog.e("ReactNative", "DevSupport is unable to get current app info");
      }
    }

    return false;
  }

  public reloadSettings(): void {
    //  if (UiThreadUtil.isOnUiThread()) {
    //    this.reload();
    //  } else {
    //            UiThreadUtil.runOnUiThread(new Runnable() {
    //                public void run() {
    //                    DevSupportManagerBase.this.reload();
    //                }
    //            });
    //        }

  }

  public isPackagerRunning(callback: PackagerStatusCallback): void {

    //  DevSupportManagerBase.this.mDevServerHelper.isPackagerRunning(callback);
    this.mDevServerHelper.isPackagerRunning(callback);

    //        Runnable checkPackagerRunning = new Runnable() {
    //            public void run() {
    //                DevSupportManagerBase.this.mDevServerHelper.isPackagerRunning(callback);
    //            }
    //};
    //if (this.mPackagerLocationCustomizer != null) {
    //  this.mPackagerLocationCustomizer.run(checkPackagerRunning);
    //} else {
    //  checkPackagerRunning.run();
    //}

  }

  //@Nullable
  public downloadBundleResourceFromUrlSync(resourceURL: string, outputFile: string): string | null { //File): File | null {
    return this.mDevServerHelper.downloadBundleResourceFromUrlSync(resourceURL, outputFile);
  }

  public handleReloadJS() {
    throw Error("should not be called")
  }

  public reloadJSFromServer(bundleURL: string, callback?: BundleLoadCallback): void {
    //        ReactMarker.logMarker(ReactMarkerConstants.DOWNLOAD_START);
    //        this.showDevLoadingViewForUrl(bundleURL);


    if (!callback) { // callback is null
      callback = ((helper: ReactInstanceDevHelper) => {
        return new class temp extends BundleLoadCallback {
          public constructor(private mHelper: ReactInstanceDevHelper) {
            super()
          }

          public onSuccess(): void {
            this.mHelper.onJSBundleLoadedFromServer();
          }
        }

        (helper)
      })(this.getReactInstanceDevHelper())
    }


    let bundleInfo = new BundleInfo();
    this.mDevServerHelper.downloadBundleFromURL(((base: DevSupportManagerBase, callBack: BundleLoadCallback) => {
      return new class temp extends DevBundleDownloadListener {
        public constructor(private mBase: DevSupportManagerBase, private mCallback: BundleLoadCallback) {
          super()
        }

        public onSuccess(): void {
          hilog.info(0x0000, DevSupportManagerBase.TAG, 'onSuccess');
          //                this.base.hideDevLoadingView();
          //                synchronized(DevSupportManagerBase.this) {
          this.mBase.mBundleStatus.isLastDownloadSucess = true;
          systemTime.getCurrentTime(false, (error, data) => {
            if (error) {
              hilog.error(0x0000, DevSupportManagerBase.TAG, `failed to systemTime.getCurrentTime because ` + JSON.stringify(error));
              return;
            }
            hilog.info(0x0000, DevSupportManagerBase.TAG, `systemTime.getCurrentTime success data : ` + data);
            this.mBase.mBundleStatus.updateTimestamp = data;
          });
          // }

          if (this.mBase.mBundleDownloadListener != null) {
            hilog.info(0x0000, DevSupportManagerBase.TAG, `mBundleDownloadListener: onSuccess`);
            this.mBase.mBundleDownloadListener.onSuccess();
          }

          //                ReactMarker.logMarker(ReactMarkerConstants.DOWNLOAD_END, bundleInfo.toJSONString());
          this.mCallback.onSuccess();
        }

        //done &  total : Integer
        public onProgress(status?: string, done?: number, total?: number): void {

          //                this.mBase.mDevLoadingViewController.updateProgress(status, done, total);
          if (this.mBase.mBundleDownloadListener != null) {
            this.mBase.mBundleDownloadListener.onProgress(status, done, total);
          }

        }

        public onFailure(cause: any): void {
          //this.mBase.hideDevLoadingView();
          //                synchronized(DevSupportManagerBase.this) {
          this.mBase.mBundleStatus.isLastDownloadSucess = false;
          //                }

          if (this.mBase.mBundleDownloadListener != null) {
            this.mBase.mBundleDownloadListener.onFailure(cause);
          }

          //                FLog.e("ReactNative", "Unable to download JS bundle", cause);
          this.mBase.reportBundleLoadingFailure(cause);
        }
      } (base, callback)
    })(this, callback), this.mJSBundleDownloadedFile, bundleURL, bundleInfo, null);
  }

  public setRemoteJSDebugEnabled(isRemoteJSDebugEnabled: boolean): void {
    if (this.mIsDevSupportEnabled) {
      //            UiThreadUtil.runOnUiThread(new Runnable() {
      //                public void run() {
      this.mDevSettings.setRemoteJSDebugEnabled(isRemoteJSDebugEnabled);
      this.handleReloadJS();
      //                }
      //            });
    }
  }

  public createSurfaceDelegate?(moduleName: string): SurfaceDelegate {
    return this.mSurfaceDelegateFactory == null ? null : this.mSurfaceDelegateFactory.createSurfaceDelegate(moduleName);
  }

  protected abstract getUniqueTag(): string;

  //@UiThread
  //private void showDevLoadingViewForUrl(String bundleUrl) {
  //  this.mDevLoadingViewController.showForUrl(bundleUrl);
  //  this.mDevLoadingViewVisible = true;
  //}
  //
  //@UiThread
  //protected void showDevLoadingViewForRemoteJSEnabled() {
  //  this.mDevLoadingViewController.showForRemoteJSEnabled();
  //  this.mDevLoadingViewVisible = true;
  //}
  //
  //@UiThread
  //protected void hideDevLoadingView() {
  //  this.mDevLoadingViewController.hide();
  //  this.mDevLoadingViewVisible = false;
  //}

  //public void fetchSplitBundleAndCreateBundleLoader(String bundlePath, final DevSupportManagerBase.CallbackWithBundleLoader callback) {
  //        final String bundleUrl = this.mDevServerHelper.getDevServerSplitBundleURL(bundlePath);
  //        final File bundleFile = new File(this.mJSSplitBundlesDir, bundlePath.replaceAll("/", "_") + ".jsbundle");
  //        UiThreadUtil.runOnUiThread(new Runnable() {
  //            public void run() {
  //                DevSupportManagerBase.this.showSplitBundleDevLoadingView(bundleUrl);
  //                DevSupportManagerBase.this.mDevServerHelper.downloadBundleFromURL(new DevBundleDownloadListener() {
  //                    public void onSuccess() {
  //                        UiThreadUtil.runOnUiThread(new Runnable() {
  //                            public void run() {
  //                                DevSupportManagerBase.this.hideSplitBundleDevLoadingView();
  //                            }
  //                        });
  //                        ReactContext context = DevSupportManagerBase.this.mCurrentContext;
  //                        if (context != null && context.hasActiveReactInstance()) {
  //                            JSBundleLoader bundleLoader = JSBundleLoader.createCachedSplitBundleFromNetworkLoader(bundleUrl, bundleFile.getAbsolutePath());
  //                            callback.onSuccess(bundleLoader);
  //                        }
  //                    }
  //
  //                    public void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total) {
  //                        DevSupportManagerBase.this.mDevLoadingViewController.updateProgress(status, done, total);
  //                    }
  //
  //                    public void onFailure(Exception cause) {
  //                        UiThreadUtil.runOnUiThread(new Runnable() {
  //                            public void run() {
  //                                DevSupportManagerBase.this.hideSplitBundleDevLoadingView();
  //                            }
  //                        });
  //                        callback.onError(bundleUrl, cause);
  //                    }
  //                }, bundleFile, bundleUrl, (BundleInfo)null);
  //            }
  //        });
  //    }
  //
  //@UiThread
  //private void showSplitBundleDevLoadingView(String bundleUrl) {
  //  this.showDevLoadingViewForUrl(bundleUrl);
  //  ++this.mPendingJSSplitBundleRequests;
  //}
  //
  //@UiThread
  //private void hideSplitBundleDevLoadingView() {
  //  if (--this.mPendingJSSplitBundleRequests == 0) {
  //    this.hideDevLoadingView();
  //  }
  //
  //}

  //@Nullable
  protected getCurrentContext(): ReactContext | null {
    return this.mCurrentContext;
  }

  //@Nullable
  protected getJSAppBundleName(): string | null {
    return this.mJSAppBundleName;
  }
  //
  //@Nullable
  //public String getLastErrorTitle() {
  //  return this.mLastErrorTitle;
  //}
  //
  //@Nullable
  //public StackFrame[] getLastErrorStack() {
  //  return this.mLastErrorStack;
  //}
  //
  //public int getLastErrorCookie() {
  //  return this.mLastErrorCookie;
  //}
  //
  //@Nullable
  //public ErrorType getLastErrorType() {
  //  return this.mLastErrorType;
  //}
  //
  //private void handleCaptureHeap(final Responder responder) {
  //  if (this.mCurrentContext != null) {
  //            JSCHeapCapture heapCapture = (JSCHeapCapture)this.mCurrentContext.getNativeModule(JSCHeapCapture.class);
  //            if (heapCapture != null) {
  //                heapCapture.captureHeap(this.mApplicationContext.getCacheDir().getPath(), new CaptureCallback() {
  //                    public void onSuccess(File capture) {
  //                        responder.respond(capture.toString());
  //                    }
  //
  //                    public void onFailure(CaptureException error) {
  //                        responder.error(error.toString());
  //                    }
  //                });
  //            }
  //
  //}
  //}
  //
  //private void updateLastErrorInfo(@Nullable String message, StackFrame[] stack, int errorCookie, ErrorType errorType) {
  //  this.mLastErrorTitle = message;
  //  this.mLastErrorStack = stack;
  //  this.mLastErrorCookie = errorCookie;
  //  this.mLastErrorType = errorType;
  //}

  protected getApplicationContext(): Context.AbilityContext { //context
    return this.mAbilityContext;
  }

  //public reloadJSFromServer1(bundleURL: string):void {
  //  this.reloadJSFromServerImpl(bundleURL, ((helper: ReactInstanceDevHelper) => {
  //    return new class temp extends BundleLoadCallback {
  //      public constructor(private mHelper: ReactInstanceDevHelper) {
  //        super()
  //      }
  //      public onSuccess(): void {
  //        this.mHelper.onJSBundleLoadedFromServer();
  //      }
  //    }(helper)
  //  })(this.getReactInstanceDevHelper()));
  //}

  protected getDevServerHelper(): DevServerHelper {
    return this.mDevServerHelper;
  }

  protected getReactInstanceDevHelper(): ReactInstanceDevHelper {
    return this.mReactInstanceDevHelper;
  }

  //public void startInspector() {
  //  if (this.mIsDevSupportEnabled) {
  //    this.mDevServerHelper.openInspectorConnection();
  //  }
  //
  //}
  //
  //public void stopInspector() {
  //  this.mDevServerHelper.closeInspectorConnection();
  //}
  //
  //public void setHotModuleReplacementEnabled(final boolean isHotModuleReplacementEnabled) {
  //  if (this.mIsDevSupportEnabled) {
  //            UiThreadUtil.runOnUiThread(new Runnable() {
  //                public void run() {
  //                    DevSupportManagerBase.this.mDevSettings.setHotModuleReplacementEnabled(isHotModuleReplacementEnabled);
  //                    DevSupportManagerBase.this.handleReloadJS();
  //                }
  //            });
  //        }
  //}

  private resetCurrentContext(reactContext?: ReactContext): void {
    if (this.mCurrentContext != reactContext) {
      this.mCurrentContext = reactContext;
      //    if (this.mDebugOverlayController != null) {
      //      this.mDebugOverlayController.setFpsDebugViewVisible(false);
      //    }

      //    if (reactContext != null) {
      //      this.mDebugOverlayController = new DebugOverlayController(reactContext);
      //    }

      if (this.mCurrentContext != null) {
        //                try {
        //                    URL sourceUrl = new URL(this.getSourceUrl());
        //                    String path = sourceUrl.getPath().substring(1);
        //                    String host = sourceUrl.getHost();
        //                    int port = sourceUrl.getPort() != -1 ? sourceUrl.getPort() : sourceUrl.getDefaultPort();
        //                    ((HMRClient)this.mCurrentContext.getJSModule(HMRClient.class)).setup("android", path, host, port, this.mDevSettings.isHotModuleReplacementEnabled());
        //                } catch (MalformedURLException var6) {
        //                    this.showNewJavaError(var6.getMessage(), var6);
        //                }
      }

      this.reloadSettings();
    }
  }
  //
  //public void setFpsDebugEnabled(isFpsDebugEnabled: boolean) {
  //  if (this.mIsDevSupportEnabled) {
  //            UiThreadUtil.runOnUiThread(new Runnable() {
  //                public void run() {
  //                    DevSupportManagerBase.this.mDevSettings.setFpsDebugEnabled(isFpsDebugEnabled);
  //                }
  //            });
  //        }
  //}
  //
  //public void toggleElementInspector() {
  //  if (this.mIsDevSupportEnabled) {
  //            UiThreadUtil.runOnUiThread(new Runnable() {
  //                public void run() {
  //                    DevSupportManagerBase.this.mDevSettings.setElementInspectorEnabled(!DevSupportManagerBase.this.mDevSettings.isElementInspectorEnabled());
  //                    DevSupportManagerBase.this.mReactInstanceDevHelper.toggleElementInspector();
  //                }
  //            });
  //        }
  //}

  private reportBundleLoadingFailure(cause: Error): void {
    //        UiThreadUtil.runOnUiThread(new Runnable() {
    //            public void run() {
    //                if (cause instanceof DebugServerException) {
    //                    DebugServerException debugServerException = (DebugServerException)cause;
    //                    DevSupportManagerBase.this.showNewJavaError(debugServerException.getMessage(), cause);
    //                } else {
    //                    DevSupportManagerBase.this.showNewJavaError(DevSupportManagerBase.this.mApplicationContext.getString(string.catalyst_reload_error), cause);
    //                }
    //
    //            }
    //        });
  }

  //private static String getReloadAppAction(Context context) {
  //  return context.getPackageName() + ".RELOAD_APP_ACTION";
  //}
  //
  //public void setPackagerLocationCustomizer(PackagerLocationCustomizer packagerLocationCustomizer) {
  //  this.mPackagerLocationCustomizer = packagerLocationCustomizer;
  //}

  //@Nullable
  //public Activity getCurrentActivity() {
  //  return this.mReactInstanceDevHelper.getCurrentActivity();
  //}

  private reload(): void {
    //  UiThreadUtil.assertOnUiThread();
    if (this.mIsDevSupportEnabled) {
      //            if (this.mDebugOverlayController != null) {
      //                this.mDebugOverlayController.setFpsDebugViewVisible(this.mDevSettings.isFpsDebugEnabled());
      //            }
      //
      //            if (!this.mIsShakeDetectorStarted) {
      //                this.mShakeDetector.start((SensorManager)this.mApplicationContext.getSystemService("sensor"));
      //                this.mIsShakeDetectorStarted = true;
      //            }

      //            if (!this.mIsReceiverRegistered) {
      //                IntentFilter filter = new IntentFilter();
      //                filter.addAction(getReloadAppAction(this.mApplicationContext));
      //                this.mApplicationContext.registerReceiver(this.mReloadAppBroadcastReceiver, filter);
      //                this.mIsReceiverRegistered = true;
      //            }
      //
      //            if (this.mDevLoadingViewVisible) {
      //                this.mDevLoadingViewController.showMessage("Reloading...");
      //            }

      //this.getClass().getSimpleName()
      this.mDevServerHelper.openPackagerConnection(DevSupportManagerBase.generateID(), ((base: DevSupportManagerBase) => {
        return new class temp extends PackagerCommandListener {
          constructor(private mBase: DevSupportManagerBase) {
            super()
          }

          public onPackagerConnected(): void {
          }

          public onPackagerDisconnected(): void {
          }

          public onPackagerReloadCommand(): void {
            this.mBase.getDevServerHelper().disableDebugger()
            this.mBase.handleReloadJS(); // in ui thread
          }

          //                public void onPackagerDevMenuCommand() {
          //                    UiThreadUtil.runOnUiThread(new Runnable() {
          //                        public void run() {
          //                            DevSupportManagerBase.this.showDevOptionsDialog();
          //                        }
          //                    });
          //                }
          //
          //                public void onCaptureHeapCommand(final Responder responder) {
          //                    UiThreadUtil.runOnUiThread(new Runnable() {
          //                        public void run() {
          //                            DevSupportManagerBase.this.handleCaptureHeap(responder);
          //                        }
          //                    });
          //                }
          //
          //                @Nullable
          //                public Map<String, RequestHandler> customCommandHandlers() {
          //                    return DevSupportManagerBase.this.mCustomPackagerCommandHandlers;
          //                }
        }(base)
      })(this));
    } else {
      //    if (this.mDebugOverlayController != null) {
      //      this.mDebugOverlayController.setFpsDebugViewVisible(false);
      //    }
      //
      //    if (this.mIsShakeDetectorStarted) {
      //      this.mShakeDetector.stop();
      //      this.mIsShakeDetectorStarted = false;
      //    }
      //
      //    if (this.mIsReceiverRegistered) {
      //      this.mApplicationContext.unregisterReceiver(this.mReloadAppBroadcastReceiver);
      //      this.mIsReceiverRegistered = false;
      //    }
      //
      //    this.hideRedboxDialog();
      //    this.hideDevOptionsDialog();
      //    this.mDevLoadingViewController.hide();
      this.mDevServerHelper.closePackagerConnection();
    }

  }
}


export interface CallbackWithBundleLoader {
  onSuccess(var1: JSBundleLoader): void;
  onError(var1: string, var2: Error): void //var : Throwable
}
